package DSMini;
import miniAES.assembly;

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.stream.IntStream;

public class dataGeneration {
    /*
    * 存储预处理的数据
    * 每一个表为15个4比特的条目，变量有c0 c1 c2 c3 c4 c5 K3[0] K3[3]
    * 存储时使用byte型的数据（8个元素进行存储15个半字），以c0 c1 c2 c3 c4 c5 K3[0]共2^28个表为一个文件存储 共16个含1.875GB的数据文件
    * */
    
    //单个文件存储的表的数量
    private static final int FILE_SIZE =16777216;
    //一个表里的字节数量
    private static final int Siza=125829120;


    public static void main(String[] args) {
        IntStream.range(0, 256).parallel().forEach(K3 ->{
            String fileName = "table_" + K3 + ".dat";
            byte tempK3= (byte) K3;
            byte K3_0= (byte) (tempK3>>4&0b00001111);
            byte K3_3= (byte) (K3&0b00001111);
            byte[] table=new byte[Siza];
            for (int SevenValue = 0; SevenValue < FILE_SIZE; SevenValue++) {
                //得到c0 c1 c2 c3 c4 c5 K3_0 ->values[0]-->values[5]
                int tempSevenValue=SevenValue;
                byte[] values=new byte[6];
                for (int i = 5; i >=0; i--) {
                    values[i]= (byte) (tempSevenValue&0b1111);
                    tempSevenValue>>=4;
                }
                //得到X0_0为0 和X0_0为x0_0的X3_0对应的值 false对应于计算X3_0
                //得到X0_0为0 和X0_0为x0_0的X3_3对应的值 true 对应于计算X3_3
                byte X30M=getX3M((byte) 0,values,K3_0,false);
                byte X33M=getX3M((byte) 0,values,K3_3,true);
                for (int i = 1; i <16 ; i++) {
                    byte X3i0M=getX3M((byte) i,values,K3_0,false);
                    byte X3i3M=getX3M((byte) i,values,K3_3,true);
                    //计算对应的4比特差分值
                    byte difference= (byte) (
                            assembly.gfMultiplication((byte) 3, (byte) (assembly.sBox[X3i0M]^assembly.sBox[X30M]))
                                    ^assembly.gfMultiplication((byte) 2, (byte) (assembly.sBox[X3i3M]^assembly.sBox[X33M])));
                    //将差分值存在table中
                    save(table,SevenValue,i-1,difference);
                }
            }
            try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(fileName))) {
                dos.write(table);
                System.out.println("Successfully wrote to file: " + fileName);
            } catch (IOException e) {
                System.out.println("Failed  wrote to file: " + fileName);
                throw new RuntimeException(e);
            }
        });
    }
     /*for (int K3 = 0; K3 < 256; K3++) {
        byte X0=0;
        String fileName = "table_" + K3 + ".dat";
        byte[] table=new byte[Siza];
        for (int SevenValue = 0; SevenValue < FILE_SIZE; SevenValue++) {
            //得到c0 c1 c2 c3 c4 c5 ->values[0]-->values[5]
            int tempSevenValue=SevenValue;
            byte[] values=new byte[6];
            for (int i = 5; i >=0; i--) {
                values[i]= (byte) (tempSevenValue&0b1111);
                tempSevenValue>>=4;
            }
            //得到X0_0为0 和X0_0为x0_0的X3_0对应的值 false对应于计算X3_0
            //得到X0_0为0 和X0_0为x0_0的X3_3对应的值 true 对应于计算X3_3
            byte X30M=getX3M(X0,values,K3,false);
            byte X33M=getX3M(X0,values,K3,true);
            for (int i = 1; i <16 ; i++) {
                byte X3i0M=getX3M((byte) i,values,K3,false);
                byte X3i3M=getX3M((byte) i,values,K3,true);
                //计算对应的4比特差分值
                byte difference= (byte) (
                        assembly.gfMultiplication((byte) 3, (byte) (assembly.sBox[X3i0M]^assembly.sBox[X30M]))
                                ^assembly.gfMultiplication((byte) 2, (byte) (assembly.sBox[X3i3M]^assembly.sBox[X33M])));
                //将差分值存在table中
                save(table,SevenValue,i-1,difference);
            }
        }
        try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(fileName))) {
            dos.write(table);
            System.out.println("Successfully wrote to file: " + fileName);
        } catch (IOException e) {
            System.out.println("Failed  wrote to file: " + fileName);
            throw new RuntimeException(e);
        }
    }
    }*/

    //根据sevenValue和i变量进行存储
    private static void save(byte[] table, int sevenValue, int i, byte difference) {
        int index = (int) (sevenValue *7.5 + (double) i/2);
        //当sevenValue为一个偶数时的处理
        byte temp=difference;
        if ((sevenValue&1)==0){
            //当一组表里的索引下表0--15为偶数时
            if ((i&1)==0){
                temp<<=4;
                table[index]=temp;
            }else {
                table[index]|=temp;
            }
        }else {
            //当一组表里的索引下表0--15为偶数时
            if ((i&1)==0){
                table[index]|=temp;
            }else {
                temp<<=4;
                table[index]=temp;
            }
        }
    }

    private static byte getX3M(byte x0, byte[] values, int K3, boolean flage) {
        byte temp0=assembly.sBox[x0] ;

        if (flage){
            //计算3S(.......)
            byte temp1 = (byte) (assembly.gfMultiplication((byte) 2, temp0)^values[1]);
            byte temp2 = (byte) (assembly.gfMultiplication((byte) 2,assembly.sBox[temp1])^values[4]);
            byte temp3= assembly.gfMultiplication((byte) 2,assembly.sBox[temp2]);
            //计算2S(......)
            byte temp4= (byte) (assembly.gfMultiplication((byte) 3,temp0)^values[0]);
            byte temp5 = (byte) (assembly.gfMultiplication((byte) 2,assembly.sBox[temp4])^values[3]);
            byte temp6= (byte) (assembly.gfMultiplication((byte) 3,assembly.sBox[temp5])^K3);

            return (byte) (temp3^temp6);
        }else {
            //计算2S(.......)
            byte temp1 = (byte) (assembly.gfMultiplication((byte) 3, temp0)^values[0]);
            byte temp2 = (byte) (assembly.gfMultiplication((byte) 3,assembly.sBox[temp1])^values[2]);
            byte temp3= assembly.gfMultiplication((byte) 3,assembly.sBox[temp2]);
            //计算3S(......)
            byte temp4= (byte) (assembly.gfMultiplication((byte) 2,temp0)^values[1]);
            byte temp5 = (byte) (assembly.gfMultiplication((byte) 3,assembly.sBox[temp4])^values[5]);
            byte temp6= (byte) ((assembly.gfMultiplication((byte) 2,assembly.sBox[temp5]))^K3);

            return (byte) (temp3^temp6);

        }
    }
}
